﻿Imports YamlDotNet.Serialization
Imports YamlDotNet.Core
Imports YamlDotNet.Serialization.NamingConventions

Public Class frmMain

    Private ClangFormatPath As String
    Private ConfigFileName As String
    Private TempleteFileName As String = IO.Path.Combine(My.Application.Info.DirectoryPath, "clang-format.templete")
    Private ManualFileName = "Clang-Format Style Options.html"
    Private CodeParentDir As String = My.Application.GetEnvironmentVariable("Temp")
    Private sbStyleFormat As New Text.StringBuilder()

#Region "// trash..."

    Private Class cStyleFormat
        Public BasedOnStyle() As String = {"LLVM", "Google", "Chromium", "Mozilla""WebKit"}
        Public AccessModifierOffset As Integer
        Public AlignAfterOpenBracket As Boolean
        Public AlignConsecutiveAssignments As Boolean
        Public AlignEscapedNewlinesLeft As Boolean
        Public AlignOperands As Boolean
        Public AlignTrailingComments As Boolean
        Public AllowAllParametersOfDeclarationOnNextLine As Boolean
        Public AllowShortBlocksOnASingleLine As Boolean
        Public AllowShortCaseLabelsOnASingleLine As Boolean
        Public AllowShortFunctionsOnASingleLine() As String = {"None", "Inline", "Empty", "All"}
        Public AllowShortIfStatementsOnASingleLine As Boolean
        Public AllowShortLoopsOnASingleLine As Boolean
        Public AlwaysBreakAfterDefinitionReturnType As Boolean
        Public AlwaysBreakBeforeMultilineStrings As Boolean
        Public AlwaysBreakTemplateDeclarations As Boolean
        Public BinPackArguments As Boolean
        Public BinPackParameters As Boolean
        Public BreakBeforeBinaryOperators() As String = {"None", "NonAssignment", "All"}
        Public BreakBeforeBraces() As String = {"Attach", "Linux", "Stroustrup", "Allman", "GNU"}
        Public BreakBeforeTernaryOperators As String
        Public BreakConstructorInitializersBeforeComma As Boolean
        Public ColumnLimit As Integer
        Public CommentPragmas As String
        Public ConstructorInitializerAllOnOneLineOrOnePerLine As Boolean
        Public ConstructorInitializerIndentWidth As Integer
        Public ContinuationIndentWidth As Integer
        Public Cpp11BracedListStyle As Boolean
        Public DerivePointerAlignment As Boolean
        Public DisableFormat As Boolean
        Public ExperimentalAutoDetectBinPacking As Boolean
        Public ForEachMacros As String
        Public IndentCaseLabels As Boolean
        Public IndentWidth As Integer
        Public IndentWrappedFunctionNames As Boolean
        Public KeepEmptyLinesAtTheStartOfBlocks As Boolean
        Public Language() As String = {"None", "Cpp", "Java", "JavaScropt", "Proto"}
        Public MacroBlockBegin As String
        Public MacroBlockEnd As String
        Public MaxEmptyLinesToKeep As Integer
        Public NamespaceIndentation() As String = {"None", "Inner", "All"}
        Public ObjCBlockIndentWidth As Integer
        Public ObjCSpaceAfterProperty As Boolean
        Public ObjCSpaceBeforeProtocolList As Boolean
        Public PenaltyBreakBeforeFirstCallParameter As Integer
        Public PenaltyBreakComment As Integer
        Public PenaltyBreakFirstLessLess As Integer
        Public PenaltyBreakString As Integer
        Public PenaltyExcessCharacter As Integer
        Public PenaltyReturnTypeOnItsOwnLine As Integer
        Public PointerAlignment() As String = {"Left", "Right", "Middle"}
        Public SpaceAfterCStyleCast As Boolean
        Public SpaceBeforeAssignmentOperators As Boolean
        Public SpaceBeforeParens() As String = {"Never", "ControlStatements", "Always"}
        Public SpaceInEmptyParentheses As Boolean
        Public SpacesBeforeTrailingComments As Integer
        Public SpacesInAngles As Boolean
        Public SpacesInCStyleCastParentheses As Boolean
        Public SpacesInContainerLiterals As Boolean
        Public SpacesInParentheses As Boolean
        Public SpacesInSquareBrackets As Boolean
        Public Standard() As String = {"Cpp03", "Cpp11", "Auto"}
        Public TabWidth As Integer
        Public UseTab() As String = {"Never", "ForIndentation", "Always"}
    End Class

    Private gStyleFormat As New Dictionary(Of String, String)() From {
        {"BasedOnStyle", ""},
        {"AccessModifierOffset", ""},
        {"AlignAfterOpenBracket", ""},
        {"AlignConsecutiveAssignments", ""},
        {"AlignEscapedNewlinesLeft", ""},
        {"AlignOperands", ""},
        {"AlignTrailingComments", ""},
        {"AllowAllParametersOfDeclarationOnNextLine", ""},
        {"AllowShortBlocksOnASingleLine", ""},
        {"AllowShortCaseLabelsOnASingleLine", ""},
        {"AllowShortFunctionsOnASingleLine", ""},
        {"AllowShortIfStatementsOnASingleLine", ""},
        {"AllowShortLoopsOnASingleLine", ""},
        {"AlwaysBreakAfterDefinitionReturnType", ""},
        {"AlwaysBreakBeforeMultilineStrings", ""},
        {"AlwaysBreakTemplateDeclarations", ""},
        {"BinPackArguments", ""},
        {"BinPackParameters", ""},
        {"BreakBeforeBinaryOperators", ""},
        {"BreakBeforeBraces", ""},
        {"BreakBeforeTernaryOperators", ""},
        {"BreakConstructorInitializersBeforeComma", ""},
        {"ColumnLimit", ""},
        {"CommentPragmas", ""},
        {"ConstructorInitializerAllOnOneLineOrOnePerLine", ""},
        {"ConstructorInitializerIndentWidth", ""},
        {"ContinuationIndentWidth", ""},
        {"Cpp11BracedListStyle", ""},
        {"DerivePointerAlignment", ""},
        {"DisableFormat", ""},
        {"ExperimentalAutoDetectBinPacking", ""},
        {"ForEachMacros", ""},
        {"IndentCaseLabels", ""},
        {"IndentWidth", ""},
        {"IndentWrappedFunctionNames", ""},
        {"KeepEmptyLinesAtTheStartOfBlocks", ""},
        {"Language", ""},
        {"MacroBlockBegin", ""},
        {"MacroBlockEnd", ""},
        {"MaxEmptyLinesToKeep", ""},
        {"NamespaceIndentation", ""},
        {"ObjCBlockIndentWidth", ""},
        {"ObjCSpaceAfterProperty", ""},
        {"ObjCSpaceBeforeProtocolList", ""},
        {"PenaltyBreakBeforeFirstCallParameter", ""},
        {"PenaltyBreakComment", ""},
        {"PenaltyBreakFirstLessLess", ""},
        {"PenaltyBreakString", ""},
        {"PenaltyExcessCharacter", ""},
        {"PenaltyReturnTypeOnItsOwnLine", ""},
        {"PointerAlignment", ""},
        {"SpaceAfterCStyleCast", ""},
        {"SpaceBeforeAssignmentOperators", ""},
        {"SpaceBeforeParens", ""},
        {"SpaceInEmptyParentheses", ""},
        {"SpacesBeforeTrailingComments", ""},
        {"SpacesInAngles", ""},
        {"SpacesInCStyleCastParentheses", ""},
        {"SpacesInContainerLiterals", ""},
        {"SpacesInParentheses", ""},
        {"SpacesInSquareBrackets", ""},
        {"Standard", ""},
        {"TabWidth", ""},
        {"UseTab", ""}
    }

#End Region

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Init()

    End Sub

    Private Sub LoadCodeFile(ByVal FileName As String)
        CodeParentDir = IO.Path.GetDirectoryName(FileName)

        txtCodePathOriginal.Text = FileName
        txtCodePathFormatted.Text = FileName
        txtPathConfig.Text = IO.Path.Combine(CodeParentDir, ConfigFileName)

        Using sr = New IO.StreamReader(FileName, System.Text.Encoding.UTF8)
            azkCodeOriginal.Text = sr.ReadToEnd()
        End Using

        If IO.File.Exists(IO.Path.Combine(CodeParentDir, ConfigFileName)) Then
            LoadConfigFile(IO.Path.Combine(CodeParentDir, ConfigFileName))
        End If
    End Sub

    Private Sub Format(ByVal FileName As String)
        tslblStatus.Text = "Formatting..."
        Format2("")
        My.Computer.FileSystem.CurrentDirectory = CodeParentDir

        SaveConfigFile(IO.Path.Combine(CodeParentDir, ConfigFileName))

        Dim psInfo As New ProcessStartInfo()

        psInfo.FileName = ClangFormatPath ' Execute file
        psInfo.Arguments = FileName
        psInfo.CreateNoWindow = True ' dont open console window
        psInfo.UseShellExecute = False ' dont use shell function
        psInfo.WorkingDirectory = CodeParentDir
        psInfo.RedirectStandardOutput = True ' redirect stdout

        Dim p As Process = Process.Start(psInfo) ' execute progtam
        Dim output = p.StandardOutput.ReadToEnd() '  read stdout

        azkCodeFormatted.Text = output '.Replace(vbLf, vbCrLf) ' Replace Nweline code

        tslblStatus.Text = "Formatted."
    End Sub

    Private Sub Format2(ByVal FileName As String)
        sbStyleFormat.Append("-style=""{")
        For Each v As KeyValuePair(Of String, String) In gStyleFormat
            sbStyleFormat.AppendFormat("{0}: {1}, ", v.Key, v.Value)
        Next
        sbStyleFormat.Append("}")
        MsgBox(sbStyleFormat.ToString())
    End Sub

    Private Sub Init()
        ClangFormatPath = My.Settings.ClangFormatPath
        ConfigFileName = My.Settings.ConfigFileName
        azkCodeOriginal.Font = My.Settings.Font
        azkCodeFormatted.Font = My.Settings.Font
        txtConfig.Font = My.Settings.Font

        LoadConfigTemplete()

        WebBrowser.Url = New Uri(IO.Path.Combine(My.Application.Info.DirectoryPath, ManualFileName) + "#configurable-format-style-options")

        azkCodeOriginal.Highlighter = Sgry.Azuki.Highlighter.Highlighters.Cpp
        azkCodeFormatted.Highlighter = Sgry.Azuki.Highlighter.Highlighters.Cpp
    End Sub

    Private Sub ManualGoTo()
        Dim tmp = IO.Path.Combine(My.Application.Info.DirectoryPath, ManualFileName) + "#" + dgvCmdOpt.SelectedRows(0).Cells(0).Value
        WebBrowser.Url = New Uri(tmp)
    End Sub

    Private Sub LoadConfigTemplete()

        If Not IO.File.Exists(TempleteFileName) Then
            MsgBox(TempleteFileName + " Is Not found.")
            Return
        End If

        Dim n = 0
        Dim line As String

        dgvCmdOpt.Columns.Add("colKey", "Key")
        dgvCmdOpt.Columns.Add("colValue", "Value")

        dgvCmdOpt.Columns(0).ReadOnly = True

        Using sr = New IO.StreamReader(TempleteFileName)
            While (sr.Peek() >= 0)
                line = sr.ReadLine()

                If line.StartsWith("#") Then
                    Continue While
                End If

                If line.StartsWith("...") Then
                    Exit While
                End If


                Dim items() = {"", "", "", ""}

                Try
                    items = line.Split(": ".ToCharArray, 4)
                Catch ex As Exception
                    Continue While
                End Try

                dgvCmdOpt.Rows.Add()
                dgvCmdOpt.Rows(n).Cells(0).Value = items(0)

                Select Case items(1)
                    Case "bool"
                        Dim cmb = New DataGridViewComboBoxCell
                        cmb.FlatStyle = FlatStyle.Flat
                        cmb.Items.AddRange({"true", "false"})
                        dgvCmdOpt.Rows(n).Cells(1) = cmb
                    Case "list"
                        Dim cmb = New DataGridViewComboBoxCell
                        cmb.FlatStyle = FlatStyle.Flat
                        cmb.Items.AddRange(items(2).Split(","))
                        dgvCmdOpt.Rows(n).Cells(1) = cmb
                    Case "int"
                        Dim txt = New DataGridViewTextBoxCell
                        dgvCmdOpt.Rows(n).Cells(1) = txt
                    Case "string"
                        Dim txt = New DataGridViewTextBoxCell
                        dgvCmdOpt.Rows(n).Cells(1) = txt
                End Select

                AddHandler dgvCmdOpt.SelectionChanged, AddressOf ManualGoTo

                n += 1
            End While
        End Using
    End Sub

    Private Sub LoadConfigTemplete2()

        If Not IO.File.Exists(TempleteFileName) Then
            MsgBox(TempleteFileName + " Is Not found.")
            Return
        End If

        Dim n = 0
        Dim line As String

        Using sr = New IO.StreamReader(TempleteFileName)
            While (sr.Peek() >= 0)
                line = sr.ReadLine()

                If line.StartsWith("#") Then
                    Continue While
                End If

                If line.StartsWith("...") Then
                    Exit While
                End If

                Dim items() = {"", "", "", ""}

                Try
                    items = line.Split(": ".ToCharArray, 4)
                Catch ex As Exception
                    Continue While
                End Try

                Select Case items(1)
                    Case "bool"
                        Dim cli = New ConfigListItem(Trim(items(0)), Trim(items(1)), ConfigListItem.ConfigListItemStyle.Checkbox)
                        pnlConfigList.Controls.Add(cli)
                        cli.Dock = DockStyle.Top
                    Case "list"
                        Dim cmb = New DataGridViewComboBoxCell
                        cmb.FlatStyle = FlatStyle.Flat
                        cmb.Items.AddRange(items(2).Split(","))
                        dgvCmdOpt.Rows(n).Cells(1) = cmb
                    Case "int"
                        Dim cli = New ConfigListItem(Trim(items(0)), Trim(items(1)), ConfigListItem.ConfigListItemStyle.Textbox)
                        pnlConfigList.Controls.Add(cli)
                        cli.Dock = DockStyle.Top
                    Case "string"
                        Dim cli = New ConfigListItem(Trim(items(0)), Trim(items(1)), ConfigListItem.ConfigListItemStyle.Textbox)
                        pnlConfigList.Controls.Add(cli)
                        cli.Dock = DockStyle.Top
                End Select

                AddHandler dgvCmdOpt.SelectionChanged, AddressOf ManualGoTo

                n += 1
            End While
        End Using
    End Sub



    Private Sub LoadConfigFile(ByVal FileName As String)
        Dim line As String
        LoadConfigYaml(FileName)
        Using sr = New IO.StreamReader(FileName)
        Do
                line = sr.ReadLine

                If String.IsNullOrEmpty(line) Then Continue Do
                If line.StartsWith("---") Then Continue Do
                If line.StartsWith("...") Then Exit Do

                Dim items() = line.Split(":")
                If items.Length < 2 Then Continue Do

                For Each v As DataGridViewRow In dgvCmdOpt.Rows
                    gStyleFormat(Trim(items(0))) = Trim(items(1))
                    If Trim(v.Cells(0).Value) = Trim(items(0)) Then
                        If TypeOf v.Cells(1) Is DataGridViewComboBoxCell Then
                            CType(v.Cells(1), DataGridViewComboBoxCell).Value = Trim(items(1))
                        Else
                            CType(v.Cells(1), DataGridViewTextBoxCell).Value = Trim(items(1))
                        End If
                        Exit For
                    End If
                Next
            Loop Until String.IsNullOrEmpty(line)
        End Using

        Using sr = New IO.StreamReader(FileName, System.Text.Encoding.UTF8)
            txtConfig.Text = sr.ReadToEnd().Replace(vbLf, vbCrLf)
        End Using
    End Sub

    Private Sub LoadConfigYaml(ByVal FileName As String)
        Dim input = New IO.StreamReader(FileName, System.Text.Encoding.UTF8)
        Dim Deserializer = New Deserializer()
        Dim cstyleformat = Deserializer.Deserialize(input)



    End Sub








    Private Sub SaveConfigFile(ByVal FileName As String)
        Using sr = New IO.StreamWriter(FileName, False, System.Text.Encoding.UTF8)
            sr.NewLine = vbLf
            sr.WriteLine("---")
            For Each v As DataGridViewRow In dgvCmdOpt.Rows
                sr.WriteLine(v.Cells(0).Value + ": " + v.Cells(1).Value)
            Next
            sr.Write("...")
        End Using
    End Sub

    Private Sub SaveConfigFile(ByVal FileName As String, ByVal Config As String)
        Using sr = New IO.StreamWriter(FileName, False, System.Text.Encoding.UTF8)
            sr.NewLine = vbLf
            sr.WriteLine(Config)
        End Using
    End Sub

    Private Sub dgvCmdOpt_CellEnter(sender As Object, e As DataGridViewCellEventArgs) Handles dgvCmdOpt.CellEnter
        dgvCmdOpt.BeginEdit(True)
    End Sub

    Private Sub dgvCmdOpt_CellLeave(sender As Object, e As DataGridViewCellEventArgs) Handles dgvCmdOpt.CellLeave
        dgvCmdOpt.EndEdit()
    End Sub

#Region "// Drag & Drop"

    Private Sub txtCodeOriginal_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles azkCodeOriginal.DragEnter
        If e.Data.GetDataPresent(DataFormats.FileDrop) Then
            e.Effect = DragDropEffects.Copy
        Else
            e.Effect = DragDropEffects.None
        End If
    End Sub

    Private Sub txtCodeOriginal_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles azkCodeOriginal.DragDrop
        LoadCodeFile(e.Data.GetData(DataFormats.FileDrop)(0))
    End Sub

#End Region

#Region "// Menu"

    Private Sub mnuFileOpenConfigFile_Click(sender As Object, e As EventArgs) Handles mnuFileOpenConfigFile.Click
        If OpenFileDialog.ShowDialog() = DialogResult.OK Then
            LoadConfigFile(OpenFileDialog.FileName)
        End If
    End Sub

    Private Sub mnuFileSaveConfigFile_Click(sender As Object, e As EventArgs) Handles mnuFileSaveConfigFile.Click
        If SaveFileDialog.ShowDialog() = DialogResult.OK Then
            SaveConfigFile(SaveFileDialog.FileName)
        End If
    End Sub

    Private Sub mnuViewFont_Click(sender As Object, e As EventArgs) Handles mnuViewFont.Click
        If FontDialog.ShowDialog() = DialogResult.OK Then
            My.Settings.Font = FontDialog.Font
            azkCodeOriginal.Font = FontDialog.Font
            azkCodeFormatted.Font = FontDialog.Font
            txtConfig.Font = FontDialog.Font
        End If
    End Sub

    Private Sub mnuFormat_Click(sender As Object, e As EventArgs)
        Format(txtCodePathOriginal.Text)
    End Sub

    Private Sub mnuToolsOptions_Click(sender As Object, e As EventArgs) Handles mnuToolsOptions.Click
        frmOptions.ShowDialog()
    End Sub

    Private Sub mnuFileExit_Click(sender As Object, e As EventArgs) Handles mnuFileExit.Click
        Me.Dispose()
    End Sub

    Private Sub mnuOpenCodeFile_Click(sender As Object, e As EventArgs) Handles mnuFileOpenCodeFile.Click
        OpenFileDialog.Title = "Open Code File..."
        If OpenFileDialog.ShowDialog() = DialogResult.OK Then
            LoadCodeFile(OpenFileDialog.FileName)
        End If
    End Sub

    Private Sub btnReloadConfigFile_Click(sender As Object, e As EventArgs) Handles btnReloadConfigFile.Click
        LoadConfigFile(txtPathConfig.Text)
    End Sub

    Private Sub btnSaveConfigFile_Click(sender As Object, e As EventArgs) Handles btnSaveConfigFile.Click
        SaveConfigFile(txtPathConfig.Text, txtConfig.Text)
    End Sub

    Private Sub mnuAbout_Click(sender As Object, e As EventArgs) Handles mnuAbout.Click
        frmAbout.ShowDialog()


        Dim btn = New Button()
        btn.Text = "iiiiii"
        pnlConfigList.Controls.Add(btn)
        btn.BringToFront()


    End Sub

    Private Sub chkOriginalProperty_CheckedChanged(sender As Object, e As EventArgs) Handles chkOriginalProperty.CheckedChanged
        splAzkPropertyOriginal.Panel2Collapsed = Not chkOriginalProperty.Checked
    End Sub

    Private Sub chkFormattedProperty_CheckedChanged(sender As Object, e As EventArgs) Handles chkFormattedProperty.CheckedChanged
        splAzkPropertyFormatted.Panel2Collapsed = Not chkFormattedProperty.Checked
    End Sub

    Private Sub txtCodePathOriginal_KeyDown(sender As Object, e As KeyEventArgs) Handles txtCodePathOriginal.KeyDown
        If e.KeyCode = Keys.Return Then
            LoadCodeFile(txtCodePathOriginal.Text)
        End If
    End Sub

    Private Sub tsbtnFormat_Click(sender As Object, e As EventArgs) Handles tsbtnFormat.Click
        Format(txtCodePathOriginal.Text)
    End Sub

    Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
        If IO.File.Exists(txtCodePathFormatted.Text) Then
            If MsgBox("Are you sure you want to overwrite?", vbOKCancel) = MsgBoxResult.Ok Then
                Using sr = New IO.StreamWriter(pptAzkFormatted.Text)
                    sr.Write(txtCodePathFormatted)
                End Using
            End If
        End If
    End Sub

    Private Sub tsbtnFont_Click(sender As Object, e As EventArgs) Handles tsbtnFont.Click
        If FontDialog.ShowDialog() = DialogResult.OK Then
            My.Settings.Font = FontDialog.Font
            azkCodeOriginal.Font = FontDialog.Font
            azkCodeFormatted.Font = FontDialog.Font
            txtConfig.Font = FontDialog.Font
        End If
    End Sub

    Private Sub btnOpenCode_Click(sender As Object, e As EventArgs) Handles btnOpenCode.Click
        OpenFileDialog.Title = "Open Code File..."
        If OpenFileDialog.ShowDialog() = DialogResult.OK Then
            LoadCodeFile(OpenFileDialog.FileName)
        End If
    End Sub

    Private Sub dgvCmdOpt_CellEndEdit(sender As Object, e As DataGridViewCellEventArgs) Handles dgvCmdOpt.CellEndEdit
        Dim key = dgvCmdOpt.SelectedRows(0).Cells(0).Value
        Dim val = dgvCmdOpt.SelectedRows(0).Cells(1).Value
        If String.IsNullOrEmpty(val) Then val = "''"
        gStyleFormat(key) = val
    End Sub

    Private Sub frmMain_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
        LoadConfigTemplete2()
    End Sub

#End Region


End Class
